package com.alibaba.travel.article.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.alibaba.travel.article.dao.UserArticleHistoryDao;
import com.alibaba.travel.article.dto.ArticleAddRequest;
import com.alibaba.travel.article.dto.ArticleResponse;
import com.alibaba.travel.article.dto.ArticleUpdateRequest;
import com.alibaba.travel.article.entity.*;
import com.alibaba.travel.article.feign.UserLikesRecordFeign;
import com.alibaba.travel.article.interceptor.LoginInterceptor;
import com.alibaba.travel.article.service.*;
import com.alibaba.travel.common.model.dto.ContentEntity;
import com.alibaba.travel.article.service.MongoService;
import com.alibaba.travel.common.model.dto.TopicLikesCountResponse;
import com.alibaba.travel.common.utils.RRException;
import com.alibaba.travel.common.utils.SnowFlakeUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.alibaba.travel.article.dao.ArticleDao;
import com.alibaba.travel.common.utils.Query;
import com.alibaba.travel.common.utils.PageUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;


@Service("articleService")
public class ArticleServiceImpl extends ServiceImpl<ArticleDao, ArticleEntity> implements ArticleService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private MongoService mongoService;

    /**
     *  查询所有公开文章
     * */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<ArticleEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("show_status", "0");
        return queryByQuery(params, queryWrapper);
    }

    /**
     *  查询所有私人文章
     * */
    @Override
    public PageUtils queryPrivateArticlePage(Map<String, Object> params) {
        checkLogin();
        //私人
        QueryWrapper<ArticleEntity> queryWrapper = new QueryWrapper<>();
        // 查询私人所有文章
        queryWrapper.eq("user_id", LoginInterceptor.userIdLocal.get());
        LoginInterceptor.userIdLocal.remove();
        return queryByQuery(params, queryWrapper);
    }

    /**
     *  通过标签查询文章
     * */
    @Override
    public PageUtils searchByTags(Map<String, Object> params) {
        MPJLambdaWrapper<ArticleEntity> mpjLambdaWrapper = new MPJLambdaWrapper<ArticleEntity>()
                .selectAll(ArticleEntity.class)
                .leftJoin(ArticleTagRelationEntity.class, ArticleTagRelationEntity::getArticleId, ArticleEntity::getId)
                .leftJoin(ArticleTagEntity.class, ArticleTagEntity::getId, ArticleTagRelationEntity::getTagId);
        Long[] ids = (Long[]) params.get("tag_ids");
        mpjLambdaWrapper.in(true, ArticleEntity::getId, ids);
        /*Arrays.stream(ids).forEach(id->{
            mpjLambdaWrapper.eq(ArticleTagEntity::getId, id);
        });*/

        return queryByQuery(params, mpjLambdaWrapper);
    }

    @Autowired
    private ArticleTagService articleTagService;

    /**
     * 通过查询参数和查询条件 查询文章
     */
    public PageUtils queryByQuery(Map<String, Object> params, Wrapper<ArticleEntity> queryWrapper) {
        if (ObjectUtils.isEmpty(queryWrapper)) {
            queryWrapper = new QueryWrapper<>();
        }

        // 查询
        IPage<ArticleEntity> page = this.page(
                new Query<ArticleEntity>().getPage(params),
                queryWrapper
        );
        // 1、查询文章内容 和 文章标题信息、文章专栏信息
        List<Long> articleIds = new ArrayList<>();
        List<ArticleResponse> articleDtoList = page.getRecords().stream().map(article -> {
            ContentEntity contentEntity = mongoTemplate.findById(article.getContentId(), ContentEntity.class);
            if (ObjectUtils.isEmpty(contentEntity)) {
                throw new RRException("文章内容不能为空");
            }
            ArticleResponse articleResponse = new ArticleResponse();
            // 1.设置点赞数，并更新
            articleIds.add(article.getId());
            BeanUtils.copyProperties(article, articleResponse);
            // 2.设置文章内容
            articleResponse.setContent(contentEntity.getContent());
            // 3. 设置文章标签信息 和 专栏信息
            setTagsAndColumn(articleResponse);

            return articleResponse;
        }).collect(Collectors.toList());

        //   异步更新数据库信息更新
        CompletableFuture.runAsync(() -> {
            updateAsync((Long[]) articleIds.toArray());
        }, executor);

        // 2、替换list
        PageUtils utils = new PageUtils(page);
        utils.setList(articleDtoList);
        return utils;
    }

    @Autowired
    private ThreadPoolExecutor executor;

    private void updateAsync(Long[] articleIds) {
        List<TopicLikesCountResponse> list = userLikesRecordFeign.getLikesNumber(articleIds).getData("list", new TypeReference<List<TopicLikesCountResponse>>() {
            });
        for (TopicLikesCountResponse response : list) {
            ArticleEntity article = new ArticleEntity();
            article.setId(response.getTopicId());
            article.setLikesNumber(response.getCount());
            this.baseMapper.updateById(article);
        }
    }


    @Override
    public boolean save(ArticleAddRequest entity) {
        checkLogin();
        ArticleEntity article = new ArticleEntity();
        // 1.保存内容
        Long contentId = SnowFlakeUtil.getDefaultSnowFlakeId();
        ContentEntity contentEntity = new ContentEntity(contentId.toString(), entity.getContent());
        mongoService.updateById(contentEntity);
        article.setContentId(contentId.toString());

        // 2.文章信息
        Long articleId = SnowFlakeUtil.getDefaultSnowFlakeId();
        article.setId(articleId);
        BeanUtils.copyProperties(entity, article);

        // 2.1 设置文章发布人信息 TODO
        Long userId = LoginInterceptor.userIdLocal.get();
        LoginInterceptor.userIdLocal.remove();
        article.setUserId(userId);

        // 3.创建文章关联关系
        createTagsRelation(articleId, entity.getTagIds());
        createColumnsRelation(articleId, entity.getColumnIds());

        return this.saveOrUpdate(article);
    }

    @Autowired
    private StringRedisTemplate redisTemplate;


    @Autowired
    private ArticleTagRelationService articleTagRelationService;


    /**
     *6 创建tags与文章的关联
     */
    private void createTagsRelation(Long articleId, Long[] ids) {
        for (Long tagId : ids) {
            // 排除已经存在的关系
            ArticleTagRelationEntity relationEntity = articleTagRelationService.getBaseMapper()
                    .selectOne(new LambdaQueryWrapper<ArticleTagRelationEntity>()
                            .eq(ArticleTagRelationEntity::getArticleId, articleId)
                            .eq(ArticleTagRelationEntity::getTagId, tagId));
            if (!ObjectUtils.isEmpty(relationEntity)) {
                /*通过抛出异常的方式跳出循环 通过return跳过当次循环*/
                continue;
            }
            ArticleTagRelationEntity entity = new ArticleTagRelationEntity();
            entity.setArticleId(articleId);
            entity.setTagId(tagId);
            articleTagRelationService.save(entity);
        }
    }
    @Autowired
    private ColumnArticleRelationService columnArticleRelationService;

    /**
     * 创建专栏 与 文章的关联
     * @param articleId
     */
    private void createColumnsRelation(Long articleId, Long[] ids) {
        for (Long columnId : ids) {
            // 判断当前关系是否已经存在
            ColumnArticleRelationEntity relationEntity = columnArticleRelationService.getBaseMapper().selectOne(new LambdaQueryWrapper<ColumnArticleRelationEntity>()
                    .eq(ColumnArticleRelationEntity::getArticleId, articleId)
                    .eq(ColumnArticleRelationEntity::getColumnId, columnId));
            if (!ObjectUtils.isEmpty(relationEntity)) {
                /*通过抛出异常的方式跳出循环 通过return跳过当次循环*/
                continue;
            }

            ColumnArticleRelationEntity relation = new ColumnArticleRelationEntity();
            relation.setArticleId(articleId);
            relation.setColumnId(columnId);
            columnArticleRelationService.save(relation);
        }
    }


    @Transactional
    public boolean update(ArticleUpdateRequest entity) {
        // 检查是否登录 文章id不能为空
        checkLogin();
        if (ObjectUtils.isEmpty(entity.getId())) {
            throw new RRException("文章id不能为空");
        }
        // 查询文章
        ArticleEntity articleEntity = this.baseMapper.selectById(entity.getId());
        // 没有报错
        if (ObjectUtils.isEmpty(articleEntity)) {
            throw new RRException("该文章不存在");
        }// 判断当前用户是否与要修改的文章发布人一致
        else if (!articleEntity.getUserId().equals(LoginInterceptor.userIdLocal.get())) {
            throw new RRException("该用户不能修改该文章");
        }
        // 有就修改
        // 1.修改文章数据库信息
        ArticleEntity article = new ArticleEntity();
        BeanUtils.copyProperties(entity, article);
        this.updateById(article);

        // 2.修改文章内容信息
        ContentEntity contentEntity = new ContentEntity(entity.getContentId(), entity.getContent());
        mongoService.updateById(contentEntity);
        return true;
    }

    private void checkLogin() {
        if (ObjectUtils.isEmpty(LoginInterceptor.userIdLocal.get())) {
            throw new RRException("用户未登录");
        }
    }

    @Override
    @Transactional
    public void delete(List<Long> list) {
        list.stream().forEach(id ->{
            ArticleEntity article = this.baseMapper.selectById(id);
            if (ObjectUtils.isEmpty(article.getContentId())) {
                throw new RRException("文章id不存在");
            }
            if (!article.getUserId().equals(LoginInterceptor.userIdLocal.get())) {
                return;
            }
            int i = this.baseMapper.deleteById(id);
            Long aLong = mongoService.removeById(article.getContentId());
            if (!(i > 0 || aLong > 0)) {
                throw new RRException("删除失败");
            }
        });
    }


    @Autowired
    private UserArticleHistoryDao userArticleHistoryDao;
    @Autowired
    private UserLikesRecordFeign userLikesRecordFeign;

    /**
     * 通过文章id查询文章
     * @return
     */
    @Override
    public ArticleResponse getDetailById(Long id) {
        if (ObjectUtils.isEmpty(id)) {
            throw new RRException("查询参数不能为空");
        }
        // 如果用户存在，则添加用户查询历史记录
        if (!ObjectUtils.isEmpty(LoginInterceptor.userIdLocal.get())) {
            // 添加用户浏览历史
            // 1.判断是否存在信息，
            LambdaQueryWrapper<UserArticleHistoryEntity> query = new LambdaQueryWrapper<UserArticleHistoryEntity>()
                    .eq(UserArticleHistoryEntity::getArticleId, id)
                    .eq(UserArticleHistoryEntity::getUserId, LoginInterceptor.userIdLocal.get());
            UserArticleHistoryEntity history = userArticleHistoryDao.selectOne(query);
            if (!ObjectUtils.isEmpty(history)) {
                // 存在则更新浏览记录
                userArticleHistoryDao.update(history, query);
            } else {
                // 2.不存在则添加记录
                history = new UserArticleHistoryEntity();
                history.setArticleId(id);
                history.setUserId(LoginInterceptor.userIdLocal.get());
                userArticleHistoryDao.insert(history);
            }
        }

        // 获取文章信息
        ArticleEntity articleEntity = this.baseMapper.selectById(id);
        ContentEntity content = mongoTemplate.findById(articleEntity.getContentId(), ContentEntity.class);

        // 更新点赞数
        // 异步更新数据库
        //   异步更新数据库信息更新
        CompletableFuture.runAsync(() -> {
            Long[] a = {articleEntity.getId()};
            updateAsync(a);
        }, executor);

        return createArticleDto(articleEntity, content);
    }

    /***
     * 创建ArticleDto
     */
    private ArticleResponse createArticleDto(ArticleEntity articleEntity, ContentEntity content) {
        ArticleResponse articleResponse = new ArticleResponse();
        BeanUtils.copyProperties(articleEntity, articleResponse);
        articleResponse.setContent(content.getContent());
        // TODO 获取并设置标签信息，专栏信息
        setTagsAndColumn(articleResponse);
        return articleResponse;
    }

    @Autowired
    private SpecialColumnService columnService;
    /**
     * 设置文章专栏信息和文章标签信息
     * @param articleResponse
     */
    private void setTagsAndColumn(ArticleResponse articleResponse) {
        Long id = articleResponse.getId();
        // 1.设置文章标签列表
        List<ArticleTagRelationEntity> articleTagRelationEntityList = articleTagRelationService.getBaseMapper().
                selectList(new LambdaQueryWrapper<ArticleTagRelationEntity>()
                .eq(ArticleTagRelationEntity::getArticleId, id));
        List<ArticleTagEntity> tagEntityList = articleTagRelationEntityList.stream().map(relation -> {
            return articleTagService.getBaseMapper().selectById(relation.getTagId());
        }).collect(Collectors.toList());
        articleResponse.setTagEntityList(tagEntityList);
        // 2.设置文章专栏信息
        List<ColumnArticleRelationEntity> columnArticleRelationEntityList = columnArticleRelationService.getBaseMapper().
                selectList(new LambdaQueryWrapper<ColumnArticleRelationEntity>()
                .eq(ColumnArticleRelationEntity::getArticleId, id));
        List<SpecialColumnEntity> columnEntityList = columnArticleRelationEntityList.stream().map(relation -> {
            return columnService.getBaseMapper().selectById(relation.getColumnId());
        }).collect(Collectors.toList());
        articleResponse.setColumnEntityList(columnEntityList);
    }

    @Override
    public List<ArticleResponse> getDetails(Long[] ids) {
        List<ArticleResponse> detailList = new ArrayList<>();
        for (Long id : ids) {
            ArticleResponse detail = getDetailById(id);
            detailList.add(detail);
        }
        return detailList;
    }

    @Override
    public List<ArticleResponse> getAllPublicArticle() {
        List<ArticleResponse> detailList = new ArrayList<>();
        List<ArticleEntity> articleEntities = this.baseMapper.selectList(
                new LambdaQueryWrapper<ArticleEntity>()
                        .eq(ArticleEntity::getShowStatus, "0"));
        for (ArticleEntity entity : articleEntities) {
            ArticleResponse detail = getDetailById(entity.getId());
            detailList.add(detail);
        }
        return detailList;
    }
}